I fear that the TERMIOS standard now being considered would impede
unnecessarily real advances in the architecture of Posix systems.

This is because it specifies at too low a level, and includes many
many things that do not need to be standardized because one does not
need to know them in order to write portable application programs.

The result is to require systems not only to provide the Unix
functionality, but actually to be implemented like Unix.  It is
hard to use advanced concepts such as remote procedure call and
indirect capabilities to implement this proposal, even though they
could easily be used to implement something that behaves "enough" like
Unix for practical purposes to be a good Posix.

The standard should avoid trying to describe all the features that
Unix has.  Instead, it should focus on telling application programmers
standard ways to accomplish the tasks that application programs must do.
We must think carefully which aspects of the behavior of a standard
interface must be standard, and which are better left up to the
system implementor.

A useful heuristic is that it should not be possible to write a
portable `stty' program using standard constructs.  If the standard
goes far enough to make this possible, it says too much, and makes it
impossible for many other systems to provide Posix emulation modes.

In terminal control, there are a few general areas that need not be
standardized to enable application programs to be portable:

* Terminal characteristics data which tell the system how to produce
standard behavior for the standard system calls.

For example, there need not be a standard way to control how much
filling is needed for various characters.  As long as the system knows
how to fill properly, application programs need not care how this
happens.  However, applications do need to be able to prevent
filling from taking place (with OPOST) so that they can do verbatim
output.

Application programs control whether erase-and-kill processing is
done, so the way to control this must be standard.  But the programs
do not see the screen, so how the system displays the results (perhaps
by echoing deleted characters on hardcopy terminals, backspacing on
character display terminals, or doing raster ops on bit map terminals)
does not need to be discussed.

* How jobs are connected to their controlling terminals.

Application programs need to know that there is a controlling
terminal, or that there may be one; but they do not need to know how
the system decides whether they have a controlling terminal.
(One exception: it may be useful to have a standard way to fork
a child with no controlling terminal).  

Consider an extreme example, CSTOPB.  No application program can
reasonably use this bit.  An application program that knows this bit
exists will run into trouble on terminals that are not connected
through uarts--hardwired terminals, network ports, or those controlled
by Emacs.  On these kinds of terminals, either there is no CSTOPB or
else changing CSTOPB will fail to have whatever effect the application
program intended (probably because it does nothing).

* Where job control is concerned, it is important to avoid precluding the
control of ability to use the terminal by means of giving different
capabilities to different processes and allowing some processes to have
the power to enable and disable the capabilities used by other processes.


Next, some specific suggestions.

* C.7.2.2

It is better not to talk about how a process can acquire a controllig
terminal or relinquish one.

Every system needs some mechanism to connect users' jobs to their
terminal, but this is an internal part of the system.  Many systems
do this in ways totally unlike Unix.  In a capability-based system
this mechanism may be totally general and may not be restricted
to terminals, or to a single device per process.  Removing such
restrictions is part of the goal of designing cleaner and more general
systems.

The only thing we need to say is how to use setpgrp() to disconnect
a process from its controlling terminal.  For the sake of capability
based systems, it is best if this is done using a new system call
that demands a descriptor for the controlling terminal as an argument.
Use of any other argument would be nonstandard.

Related control flags such as HUPCL are also better left unmentioned.

* C.7.2.4

All we need to standardize about job process groups is enough to make
it possible to write a portable shell using standard constructs.
We need ways to do these things:

**1* make a process the leader of a new job process group.

**2* grant permission to use the terminal to a child's
job process group, or revoke permission.

**3* grab the ability to use the terminal directly, after having
given a child permission.  This is not necessarily the same thing
as the previous one.  Special care is required to define a common
interface for both *2* and *3*; see below.

**4* control what should happen to the process when it tries
to read or write while it lacks permission; and, find out when
this has occurred.

A standard should *not* say:

** whether more than one child process group can be given permission
simultaneously by one parent.

** whether the parent still has permission to use the terminal
after giving permission to a child's process group.

** what happens to the relation between the parent and the child
vis-a-vis use of the terminal if the grandparent takes permission away
from the parent.  On Unix systems, this is unpredictable.  On
capability-based systems, permission propagates from the top of the
tree of processes, and each process can allow or disallow permission
to propagate to each child.

** whether it is an error to grant or revoke a child's permission
while the parent does not have permission.

** any standard way for a child take permission when not given
permission by its parent.  It is easy to implement doing this on Unix,
but on capability-based systems the child may not get a new capability
whose access the parent will enable and disable.  Then the child will be
completely unable to do this.

** any standard way to use the terminal without permission.
This too is probably impossible to implement on capability-based systems.
In fact, the parent might be able to change where the child's capability
points in addition to turning it on or off.  Imagine being able to
redirect the stdout of a program already running.

** that one can do anything that affects the behavior of the
controlling terminal without using a descriptor for it.
This includes setpgrp!

Here are my specific proposals:

**1* make a process the leader of a new job process group.

Use a new function new_pgrp (TERMDESC, GETACCESS);

TERMDESC must be a descriptor for the controlling terminal; that is
the only standard value, and what happens if it is not that is
undefined by the standard.  On some systems, each open file (even a
disk file!) will be able to have its own independent set of process
groups.

GETACCESS, if nonzero, says to set the pgrp of the terminal to the
newly created one.  If zero is used here, only the parent has the
ability subsequently to use change_term_pgrp (below) to let grant the
use of the terminal.  GETACCESS makes sense because new_pgrp will be
used between the fork and the exec, so the choice of GETACCESS value
will be under control of the parent program even though not the parent
process.

It is nonstandard to do new_pgrp in a process that has already
done an exec.  It is recommended for systems not to permit
new_pgrp with nonzero GETACCESS (at least) after an exec.
Unix 4.2 will, however, permit it, if this call is implemented for
it in the straightforward way using standard 4.2 facilities.

**2* grant permission for terminal use to a child's job process group,
or revoke permission.

**3* grab the ability to use the terminal directly, after having
given a child permission.  This is not necessarily the same thing
as the previous one.

I propose one new system call to do both of these things.

The current method, which involves specifying handling for SIGTTOU (or
is it SIGTTIN) and then changing the process group of the terminal, is
very unclean and constrains other parts of the system such as how
signals are implemented.

We use a new function change_term_pgrp (T, G1, G2);

which means, "if terminal T's job process group is now G1, change it
to G2".  Zero as G1 or G2 stands for the job process group of this
process.

Each of G1 and G2 must be zero or the pid of a child which is a job
process group leader; otherwise the results are undefined, but it is
recommended to return an error and do nothing.

The normal case for this function is that the terminal's current
process group is that specified by G1, or belongs to a descendant
process of the process specified by G1.  In the normal case, the
function always succeeds and performs as specified, assuming the
argument G2 is valid.

In the abnormal case, it is not specified what happens.  It is
possible for the function to have its normal effect, but only later,
once some grandparent gives the parent permission once again.  It is
possible for it to signal SIGTTOU or SIGTTIN (choose one) in which
case the results can depend on whether the signal is handled.  If
SIGTTIN or SIGTTOU (whichever) is ignored, it is possible for it to be
a no-op, or it is possible for it to set the terminal's pgrp to G2
anyway.

It is not necessary to speak about matching uids, because in standard
usage the real uids are always the same.  We need not speak about
whether root is permitted to do anything special.

change_term_pgrp can be implemented on Unix as a library routine
that uses the old ugly recipe involving signal (SIGTTOU).

On some other systems, where each child job process group can be
controlled independently and the parent can always use the terminal
regardless of them, this call would turn off permission for group G1
(if that is not zero) and then turn on permission for group G2 (if G2
is not zero).  G1 is not needed on Unix, but it is essential on
systems where multiple children can have permission independently.  It
is never very hard for a shell to remember who it last gave permission
to.

Thus the least common denominator of functionality--that which is
possible on Unix--can be had in a standard way that can be implemented
on many other kinds of system architectures.

**4* is handled well by the proposal, except that it should not
be specified that any actual input or output can take place if
the signal SIGTTIN or SIGTTOU is ignored.  It should be permitted
for the read or write to hang or be ignored; or the system could
provide nonstandard ways to control which of these happens.

* C.7.2.5

"A call to close () on a terminal device ... all pending input
is discarded."

This is a disaster!  I fork a subprocess, and it does freopen on
stdin, and that throws away terminal input???

Perhaps there was an omission in the text of this part of the
standard.  Perhaps it only means to apply to closing the last open
descriptor on the terminal.  This falls into the domain of how
controlling terminals are connected with users' jobs, which should not
be addressed; so if this is what is meant, it would be better not to
mention it.

* C.7.2.6.1

It should not be required that the escape character for verbatim
entry is \.  It is enough to suggest that there be such a
character.  In fact, this is a poor choice, because it is cleanest
if all printing characters are free of any meaning for input editing.

* C.7.2.8

It should not be specified that you cannot escape
the other special characters such as INTR, QUIT, SUSP...
It is ok to permit this to be possible and also permit it
to be impossible.  A system might want to allow this if the
escape character is nonprinting (such as ^V) but not allow this
if the escape character is printing (such as \); or it could
have another nonstandard flag that controls this decision.

* C.7.2.12

The only flag that an application program needs to know about is OPOST, so
it would be a good idea to omit discussion of the other fields.

If they are not omitted, then at least the initial values of variables
that control how filling should be done should not be specified, since
many systems will want to initialize these automatically according to
what is known about the terminal.

* C.7.2.13

The only information in c_cflag that is needed by an application
program is the baud rate, and possibly PARENB (I am not sure;
depending on the meaning of some of the bits in other words,
perhaps it is not necessary to deal with PARENB in order to
send 8-bit data.  That would be a good idea in any case.)

It would be better not to mention the others in the standard.

Encoding the baud rate in this way is very fragile; we can be
sure that baud rates will exist that cannot be described.
It would be better to represent the baud rates simply as binary
numbers stored in 32-bit fields.  It is even possible to define
ways of doing this that do not require a change in the
`struct termios', though that interface would only approximately
work if the baud rate were not one it can describe.
Simply define a new ioctl for getting "real" access to the
baud rates.

* C.7.2.14

It would be better to omit mention of ECHOE, ECHOPRT and ECHOKE
because these really pertain to a style of use of the terminal.
This information really depends on the kind of terminal you have,
not on which application program is running.

We should standardize interfaces by which application programs say
what they want done, at a level that is meaningful for the application
program.  Thus, whether echoing should be done, and whether erase and
kill should be done, are things that application programs need to control.
But *how* the echoing looks, or how erase and kill processing looks,
should be considered part of the internals of the system.  Suppose
the system is window-oriented.  Should it still be required to provide
the functionality of ECHOPRT, which is intended for printing terminals?
If not, what use is there in mentioning ECHOPRT if it may not do anything?
It is nice for a system to show erased characters on a printing terminal
by reechoing them, but even if it fails to do this, that is not a concern
for the Posix standard.  Standard Posix application programs will "work"
according to this systems idea of what "working" means, which does not
include reechoing the erased characters.

PAGEOUT should be part of the standard, but the details of how and
when the system pauses, or how the user can cause resumption, should
not be specified.  It is enough if the system interprets PAGEOUT by
pausing often enough to facilitate reading the output and gives the
user a convenient way to say when to resume.

The Incompatible Timesharing System offers the program the opportunity
to get a signal when it attempts to write a character that will cause
a pause to happen.  When this feature is in use, the system does not
pause; it expects the signal handler to print "--more--" or whatever
it likes, and then to wait for input.  The standard should not
preclude offering this as an optional way to "pause".  Saying nothing
about how "pausing" works is the easiest way.

* WRAP

I wonder how the system knows what column the cursor is in.  It cannot
always know.  If all programs that want to do cursor control are
expected to turn off all output postprocessing, then WRAP need not be
part of the standard (assuming that OPOST overrides WRAP, as I hope it
does) because application programs that want postprocessing don't need
to know whether the wrapping takes place in the terminal or in the
system.

It would be clearer to put WRAP in c_oflag.

* C.7.2.15

There needs to be a standard for how to disable any one of
the special characters such as INTR, QUIT, etc.

This cannot be done by storing a value that "isn't a real character
code" because there are none!  For example 0377, which is often used
to disable one of these features.  is the character Meta-Delete, which
is a commonly used Emacs command.

Some Unix systems treat 0377 specially: it really does mean "disable
this function".  Others currently use this to mean that Meta-Delete
should have the function.

I think that defining 0377 to mean "disable" would be an adequate
solution.  A slightly better solution would allow any character code
whatever to be specified, and have "disable" as another alternative.
For example, the "characters" could actually be shorts, and then a
value out of range as a character could mean "disable".  There could
be a standard name for one such value that is recommended for this
use.

Some systems with special terminals may have special keyboard keys for
such functions as suspending and editing.  I think we should say that
it is ok for such systems to ignore the characters specified by the
application program.  Their users won't mind; they know which special
keys to use and won't be confused if those same keys work even when
they run a program that normally (on ASCII keyboards) wants to select
special keys.

* C.7.2.16

Since TCSBRK is a complicated combination of other calls defined
here, perhaps it should be deleted from the standard.

TCEXCL may not make any sense on some systems, so it should not be
required to have any effect.  It may be useful to specify the name and
its calling sequence as a standard, and say that if it makes sense to
have exclusive reservation of a terminal then this is the way to do
it; otherwise this call should do nothing.

TIOCSPGRP should be replaced by change_term_pgrp, as described above,
and TIOCGPGRP should be eliminated, because there is no way to define
the one-and-only pgrp of the terminal on systems where permission
can be granted independently to various children.

* Several sections say that "the initial value is all bits clear."

Surely this does not mean that an application program should expect
such fields as OPOST and ICANON to be zero when it is started.  What,
then, does it mean?

If the initial value means "when the system is started" or "when
the getty starts running", that is something the standard should not
talk about.  There may not be such a thing as a getty.

The only kind of initial value that would be useful to the users of
the standard, the writers of portable application programs, is the
value when an application program is started.  But nothing can be said
about most of the bits at that time, because they depend on the kind
of terminal on and the user's preferences, and system architecture.

You might think it is possible to say, for example, that ICANON will
be 1 when an application program is started.  This does not depend on
the kind of terminal, and few users are likely to prefer no input
editing.  But this is not true when the program is running under Emacs
with Emacs sending it input from an editor buffer, even though the
user does have an input editing capability.

It is best to say nothing about any sort of "initial state" for the
contents of the termios structure.  When programs that care about the
state, it is enough that the standard says how to set up that state.
For other programs (most programs) it is sufficient to assume that the
bits are set the way the user or shell considered reasonable.  That is
all that is needed for writing portable programs.
